package com.pyrsana.faith.retreat

import org.junit.internal.runners.statements.FailOnTimeout;
import org.springframework.dao.DataIntegrityViolationException

import com.pyrsana.faith.membership.Profile

import grails.plugins.springsecurity.Secured

class RetreatController {

    static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

    def springSecurityService
    
    def index() {
        redirect(action: "list", params: params)
    }

    def list() {
        params.max = Math.min(params.max ? params.int('max') : 10, 100)
        [retreatInstanceList: Retreat.list(params), retreatInstanceTotal: Retreat.count()]
    }
    
    @Secured(['IS_AUTHENTICATED_REMEMBERED'])
    def register() {
        Retreat retreatInstance = Retreat.get(params.id)
        if (!retreatInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
            return
        }

        // Retrieve existing registration, if possible. Create new one if doesn't exist:
        Registration registration
        if (springSecurityService.currentUser.authorities.find {it.authority == 'ROLE_ADMIN' || it.authority == 'ROLE_DIRECTOR' } && params.registrationId) {
            registration = Registration.get(params.registrationId)
        }
        else {
            def currentProfile = springSecurityService.currentUser.profile
            registration = retreatInstance.attendees?.find { it.profile == currentProfile }
        }
        
        // Issue messages about incomplete requirements to user:
        if (registration) {
            if (!registration.completed) {
                registration.errors.reject("Registration is incomplete!")
            }
            if (!registration.formsSubmitted) {
                registration.errors.reject("Physical forms have not been received.")
            }
            if (!registration.paid) {
                registration.errors.reject("Payment has not been received.")
            }
            if (registration.errors.errorCount == 0) {
                flash.message = 'You are completely registered!'
            }
        }
        else {
            registration = new Registration()
        }
        
        [retreat: retreatInstance, registration: registration]
    }

    @Secured(['IS_AUTHENTICATED_REMEMBERED'])
    def saveRegistration() {
        // Determine retreat to save registration for:
        Retreat retreat = Retreat.get(params.int('retreatId'))
        if (!retreat) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.retreatId])
            params.id = params.retreatId
            redirect(action: "register", params:params)
            return
        }
        
        // Determine profile to save registration for:
        Profile profile = springSecurityService.currentUser.authorities.find {it.authority == 'ROLE_ADMIN' || it.authority == 'ROLE_DIRECTOR' } && params.profileId ? Profile.get(params.profileId) : springSecurityService.currentUser.profile
        
        Registration registration
        if (params.registrationId != '') {
            registration = Registration.get(params.int('registrationId'))
            if (!registration || registration.profile != profile) {
                // User lacks permissions to update desired registration. Get proper registration:
                registration = Registration.findByRetreatAndProfile(retreat, profile)
            }
        }
        
        // New registration if could not retrieve one:
        if (!registration) {
            registration = new Registration(retreat:retreat, profile:profile, signed:false, formsSubmitted:false, paid:false)
        }
        
        // Fill registration with given parameters:
        registration.tshirtSize = params.tshirtSize
        registration.homeChurch = params.homeChurch
        registration.signer = params.signer
        registration.emergencyContact = params.emergencyContact
        registration.emergencyContactDayPhone = params.emergencyContactDayPhone
        registration.emergencyContactNightPhone = params.emergencyContactNightPhone
        registration.insuranceCompany = params.insuranceCompany
        registration.insurancePolicy = params.insurancePolicy
        registration.notes = params.notes
        registration.signed = params.signed
        
        // Must have proper permissions for current profile not to match registration profile: 
        if (springSecurityService.currentUser.profile != profile) {
            registration.formsSubmitted = params.formsSubmitted ?: false
            registration.paid = params.paid ?: false
            registration.completed = params.completed ?: false
        }
        
        // Ride requests
        Map<String, Object> rideRequestParams = params.findAll { key, value -> key.toString().startsWith("transportationLeg.") }
        Set<Long> transportationLegRequestIds = new HashSet<Long>(rideRequestParams.size())
        rideRequestParams.each { key, value ->
            transportationLegRequestIds << Long.parseLong(key.replace("transportationLeg.", ""))
        }
        retreat.transportationLegs.each { leg ->
            RideRequest rideRequest = registration.rideRequests.find { it.leg == leg }
            if (transportationLegRequestIds.contains(leg.id) && !rideRequest) {
                registration.addToRideRequests(new RideRequest(leg:leg))
            }
            else if (rideRequest && !transportationLegRequestIds.contains(leg.id)) {
                registration.removeFromRideRequests(rideRequest)
                rideRequest.delete()
            }
        }
        
        // Workshop requests
        Map<String, Object> workshopRequestParams = params.findAll { key, value -> key.toString().startsWith("workshop.") }
        workshopRequestParams.each { key, value ->
            Workshop workshop = Workshop.get(Long.parseLong(key.replace("workshop.", "")))
            if (workshop) {
                WorkshopRequest workshopRequest = registration.workshopRequests?.find { it.workshop == workshop }
                if (!workshopRequest) {
                    workshopRequest = new WorkshopRequest(workshop:workshop)
                    registration.addToWorkshopRequests(workshopRequest)
                }
                workshopRequest.rank = Integer.parseInt(value)
            }
        }
        
        if (registration.save(flush:true)) {
            flash.message = 'Saved registration.'
        }
        else {
            flash.message = 'Failed to save registration.'
        }
        
        redirect(action: 'register', params: [id:retreat.id, registrationId:registration.id])
    }
    
    @Secured(['IS_AUTHENTICATED_REMEMBERED'])
    def deleteRegistration() {
        def registrationId = params.registrationId ?: params.id
        Registration registration = Registration.get(registrationId)

        if (registration && (springSecurityService.currentUser.authorities.find {it.authority == 'ROLE_ADMIN' || it.authority == 'ROLE_DIRECTOR' } || springSecurityService.currentUser.profile == registration.profile)) {
            try {
                registration.delete(flush: true)
                flash.message = 'Registration deleted.'
                redirect(action: "register", id:registration.retreat.id)
                return
            }
            catch (DataIntegrityViolationException e) {
            }
        }
        
        flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'registration.label', default: 'Registration'), registrationId])
        redirect(action: "register", id:registration.retreat.id)
        return
    }
    
    @Secured(['ROLE_ADMIN'])
    def registrations() {
        Retreat retreat = Retreat.get(params.id)
        if (!retreat) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
            return
        }
        else {
			if (!params.sort) {
				params.sort = "dateCreated"
			}
			def registrations = retreat?.attendees.sort{
				a, b ->
					def aParam = a."${params.sort}"
					def bParam = b."${params.sort}"
					
					if (!(aParam instanceof Comparable) && !(bParam instanceof Comparable)) {
						aParam = aParam?.toString()?.trim()
						bParam = bParam?.toString()?.trim()
					}
					
					if (params.order == 'desc') {
						bParam <=> aParam
					}
					else {
						aParam <=> bParam
					}
			}
            [retreat:retreat, registrations:registrations]
        }
    }
    
    @Secured(['ROLE_ADMIN, ROLE_DIRECTOR'])
    def create() {
        [retreatInstance: new Retreat(params)]
    }

    @Secured(['ROLE_ADMIN, ROLE_DIRECTOR'])
    def save() {
        def retreatInstance = new Retreat(params)
        if (!retreatInstance.save(flush: true)) {
            render(view: "create", model: [retreatInstance: retreatInstance])
            return
        }

		flash.message = message(code: 'default.created.message', args: [message(code: 'retreat.label', default: 'Retreat'), retreatInstance.id])
        redirect(action: "show", id: retreatInstance.id)
    }

    def show() {
        def retreatInstance = Retreat.get(params.id)
        if (!retreatInstance) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
            return
        }

        [retreatInstance: retreatInstance]
    }

    @Secured(['ROLE_ADMIN, ROLE_DIRECTOR'])
    def edit() {
        def retreatInstance = Retreat.get(params.id)
        if (!retreatInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
            return
        }

        [retreatInstance: retreatInstance]
    }

    @Secured(['ROLE_ADMIN, ROLE_DIRECTOR'])
    def update() {
        def retreatInstance = Retreat.get(params.id)
        if (!retreatInstance) {
            flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
            return
        }

        if (params.version) {
            def version = params.version.toLong()
            if (retreatInstance.version > version) {
                retreatInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
                          [message(code: 'retreat.label', default: 'Retreat')] as Object[],
                          "Another user has updated this Retreat while you were editing")
                render(view: "edit", model: [retreatInstance: retreatInstance])
                return
            }
        }

        retreatInstance.properties = params

        if (!retreatInstance.save(flush: true)) {
            render(view: "edit", model: [retreatInstance: retreatInstance])
            return
        }

		flash.message = message(code: 'default.updated.message', args: [message(code: 'retreat.label', default: 'Retreat'), retreatInstance.id])
        redirect(action: "show", id: retreatInstance.id)
    }

    @Secured(['ROLE_ADMIN, ROLE_DIRECTOR'])
    def delete() {
        def retreatInstance = Retreat.get(params.id)
        if (!retreatInstance) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
            return
        }

        try {
            retreatInstance.delete(flush: true)
			flash.message = message(code: 'default.deleted.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "list")
        }
        catch (DataIntegrityViolationException e) {
			flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'retreat.label', default: 'Retreat'), params.id])
            redirect(action: "show", id: params.id)
        }
    }
}
